package model

import (
	"crypto/md5"
	"database/sql"
	"fmt"
	"gpt-api/framework/db"
	"io"
	"time"
)

type Exchange struct {
	db.BaseModel
	Code         string       `json:"code" gorm:"column:code;type:char(80);comment:兑换码"`
	CodeStatus   int8         `json:"code_status" gorm:"column:code_status;type:int;default:0;comment:兑换码状态,0=未使用,1=已使用"`
	UserId       uint64       `json:"user_id" gorm:"column:user_id;type:int;default:0;comment:用户ID"`
	Score        int          `json:"score" gorm:"column:score;type:int;default:0;comment:兑换码对应的积分"`
	ExchangeTime sql.NullTime `json:"exchange_time" gorm:"column:exchange_time;type:timestamptz;comment:兑换时间"`
}

func (Exchange) TableName() string {
	return "exchange"
}

// 创建兑换码
func (e *Exchange) Create(database *db.DB) error {
	return database.Create(e).Error
}

// 根据兑换码查询兑换信息
func (e Exchange) GetExchangeByCode(database *db.DB, code string) (Exchange, error) {
	var exchange Exchange
	err := database.Model(&Exchange{}).Where("code = ?", code).First(&exchange).Error
	return exchange, err
}

// 根据用户ID查询兑换码列表
func (e Exchange) GetExchangesByUserId(database *db.DB, userId uint64) ([]Exchange, error) {
	var exchanges []Exchange
	err := database.Model(&Exchange{}).Where("user_id = ?", userId).Find(&exchanges).Error
	return exchanges, err
}

// 生成兑换码
func (e *Exchange) GenerateExchangeCode(database *db.DB, score int) error {
	e.Code = e.GenerateCode()
	e.CodeStatus = 0
	e.UserId = 0
	e.Score = score
	return e.Create(database)
}

// 生成码
func (e *Exchange) GenerateCode() string {
	//  当前时间戳进行MD5加密然后每隔4位加一个-
	timestamp := time.Now().UnixNano()
	// 对时间戳进行MD5加密
	var md = md5.New()
	io.WriteString(md, fmt.Sprintf("%d", timestamp))
	md5Code := md.Sum(nil)
	md5CodeStr := fmt.Sprintf("%x", md5Code)
	// 将MD5加密后的字符串每隔4位加一个-,字母转大写
	code := ""
	for i := 0; i < len(md5CodeStr); i++ {
		code += string(md5CodeStr[i])
		if (i+1)%4 == 0 && i != len(md5CodeStr)-1 {
			code += "-"
		}
	}
	return code
}

// 根据兑换码查询兑换码信息
func (e Exchange) GetExchangeCodeByCode(database *db.DB, code string) (Exchange, error) {
	var exchange Exchange
	err := database.Model(&Exchange{}).Where("code = ?", code).First(&exchange).Error
	return exchange, err
}

// 根据ID查询兑换码信息
func (e Exchange) GetExchangeCodeById(database *db.DB, id uint64) (Exchange, error) {
	var exchange Exchange
	err := database.Model(&Exchange{}).Where("id = ?", id).First(&exchange).Error
	return exchange, err
}

// 更新兑换码状态
func (e *Exchange) UpdateExchangeCodeStatus(database *db.DB, id uint64, userId uint64) error {
	return database.Model(&Exchange{}).Where("id = ?", id).Updates(map[string]interface{}{
		"code_status":   1,
		"user_id":       userId,
		"exchange_time": time.Now(),
	}).Error
}

// 兑换
func (e *Exchange) Ex(database *db.DB, id uint64, userId uint64) error {
	// 开启事务
	tx := database.Begin()

	// 查询兑换码
	exchange, err := e.GetExchangeCodeById(database, id)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 兑换码状态
	if exchange.CodeStatus == 1 {
		tx.Rollback()
		return fmt.Errorf("exchange code used")
	}

	// 更新兑换码状态
	err = e.UpdateExchangeCodeStatus(database, id, userId)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 更新用户积分
	user := Users{}
	userInfo, err := user.GetUserInfoById(database, userId)
	if err != nil {
		tx.Rollback()
		return err
	}
	userInfo.Score += exchange.Score
	err = userInfo.Update(database)
	if err != nil {
		tx.Rollback()
		return err
	}

	score := Score{
		UserId:    uint(userId),
		Score:     exchange.Score,
		Comment:   "兑换码兑换" + fmt.Sprintf("%d", exchange.Score) + "积分",
		ScoreType: 7,
	}
	err = score.Create(database)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	tx.Commit()
	return nil
}
